#include "DevicesTime.h"
#include "DevicesKey.h"


KeyType g_typeKey;


void vKeyInit(void)
{
    gpio_config_t gpio_conf = {0};

    gpio_reset_pin(KEY_RESET_Pin);
    gpio_conf.pin_bit_mask = BIT64(KEY_RESET_Pin);
    gpio_conf.mode = GPIO_MODE_INPUT;
    gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
    gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
    gpio_conf.intr_type = GPIO_INTR_DISABLE;
    gpio_config(&gpio_conf);

    g_typeKey.uiKeyValueGet = uiKeyValueGet;
}

/*
Return Value:   按键组合序号（头文件里有定义）
Parameters:     void
Description:    读取当前按键状态
*/
uint32_t uiKeyValueGet(void)
{
    uint32_t Key = KEY_ALL;
    uint8_t i;

    for(i = 0; i < 8; ++i)
    {
        if(0 != gpio_ll_get_level(&GPIO, KEY_RESET_Pin))
            Key &= ~KEY_RESET;
    }

    return Key;
}

/*
 * Return:      按键状态
 * Parameters:  Value_new:新按键键值; Value_old:旧按键键值;
 * Description: 按键状态获取
 */
static KeyStateEnum enumKeyStateGet(uint32_t uiNew, uint32_t uiOld)
{
    if(uiNew == uiOld)                      /* 当前按键值与上次按键值相同 */
        return keyEqual;
    else if((uiNew & uiOld) == uiOld)       /* 当前按键值在上次按键值基础上增加了新按键 */
        return keyDown;
    else if((uiNew | uiOld) == uiOld)       /* 当前按键值在上次按键值基础上减少了旧按键 */
        return keyUp;
    else
        return keyDownAndUp;
}

/*
 * Return:      KeyStateEnum：按键状态机的状态
 * Parameters:  ptypeKeyMachine: 按键结构消息
 * Description: 按键状态获取
 */
KeyStateEnum enumKeyMachine(KeyType *ptypeKey)
{
    uint32_t uiKeyNew;
    int32_t iTimeNow = lTimebaseGet() / 1000;

    if((ptypeKey == NULL) || (ptypeKey->uiKeyValueGet == NULL))
        return keyNormal;

    uiKeyNew = ptypeKey->uiKeyValueGet();

    /* 记录时间、键值变化 */
    switch(enumKeyStateGet(uiKeyNew, ptypeKey->valueLast))
    {
        /* 记录按键按下时间、变化总键值 */
        case keyDown:
        case keyDownAndUp:
            ptypeKey->valueDown = uiKeyNew;
            ptypeKey->timeDown  = iTimeNow;
            ptypeKey->valueLast = uiKeyNew;
            ptypeKey->state     = keyDown;
            ptypeKey->stateLast = ptypeKey->state;
            ++ptypeKey->cntCombo;
            break;

        /* 记录按键松开时间、变化总键值 */
        case keyUp:
            ptypeKey->valueUp  |= ptypeKey->valueLast & (~uiKeyNew);
            ptypeKey->timeUp    = iTimeNow;
            ptypeKey->valueLast = uiKeyNew;
            ptypeKey->state     = (ptypeKey->state & ~keyDown) | keyUp;
            ptypeKey->stateLast = ptypeKey->state;
            break;

        default: break;
    }

    if(ptypeKey->stateLast == keyUp)
    {
        ptypeKey->cntCombo = 0;
        return keyNormal;
    }

    /* 按键状态转换 */
    switch((uint32_t)ptypeKey->state)
    {
        case keyDown:
            if((iTimeNow - ptypeKey->timeDown) >= KEY_SHORT_TIME)
            {
                ptypeKey->state |= keyShort;
                return ptypeKey->state;
            }
            break;

        case keyDown | keyShort:
            if((iTimeNow - ptypeKey->timeDown) >= KEY_LONG_TIME)
            {
                ptypeKey->state = (ptypeKey->state & ~keyShort) | keyLong;
                return ptypeKey->state;
            }
            break;

        case keyDown | keyLong:
            if((iTimeNow - ptypeKey->timeDown) >= KEY_CONTINUE_TIME)
            {
                ptypeKey->state = (ptypeKey->state & ~keyLong) | keyContinuous;
            }
            break;

        case keyDown | keyContinuous:
            if((iTimeNow - ptypeKey->timeDown) >= KEY_CONTINUE_INTERVAL_TIME)
            {
                /* 持续按键，重新计时 */
                ptypeKey->timeDown = iTimeNow;
                return ptypeKey->state;
            }
            break;

        case keyUp | keyShort:
        case keyUp | keyLong:
        case keyUp | keyContinuous:
            if(((iTimeNow - ptypeKey->timeUp) >= KEY_UP_TIME) && (uiKeyNew == 0))
            {
                ptypeKey->stateLast = keyUp;
                return ptypeKey->state;
            }
            break;

        default : break;
    }

    return keyNormal;
}
